home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 5 / BBS in a Box -Volume V (BBS in a Box) (April 1992).iso / Files / Prog / T / TransDisplay2p.cpt / TransDisplay.p < prev    next >
Encoding:
Text File  |  1988-12-09  |  27.6 KB  |  1,084 lines  |  [TEXT/PJMM]

  1. {    TransDisplay version 1.0 - TransSkel plug-in module supporting}
  2. {    an arbitrary number of generic display windows with memory.}
  3.  
  4. {    TransSkel and TransDisplay are public domain, and are written by:}
  5.  
  6. {            Paul DuBois}
  7. {            Wisconsin Regional Primate Research Center}
  8. {            1220 Capital Court}
  9. {            Madison WI  53706  USA}
  10.  
  11. {    UUCP:        [allegra,ihnp4,seismo]!uwvax !uwmacc !dubois }
  12. {    ARPA :     dubois @ unix.macc.wisc.edu }
  13. {                dubois @ rhesus.primate.wisc.edu }
  14.  
  15. {    The Pascal Version of TransSkel is public domain and was ported by        }
  16.  
  17. {            Owen Hartnett            }
  18. {            Ωhm Software            }
  19. {            163 Richard Drive        }
  20. {            Tiverton, RI 02878        }
  21.  
  22. {    CSNET:    omh@cs.brown.edu.CSNET                                             }
  23. {    ARPA:        omh%cs.brown.edu@relay.cs.net-relay.ARPA                        }
  24. {    UUCP:        [ihnp4,allegra]!brunix !omh                                            }
  25.  
  26. {    Psychic Wavelength:  182.2245 Meters  (sorry, couldn't resist)    }
  27.  
  28. {    This version of TransDisplay written for Lightspeed Pascal.  Lightspeed Pascal}
  29. {    is a trademark of:}
  30. {            THINK Technologies, Inc}
  31. {            420 Bedford Street  Suite 350}
  32. {            Lexington, MA  02173  USA}
  33.  
  34.  
  35.  { History}
  36. {  08/25/86    Genesis.  Beta version.}
  37. {  09/15/86    Changed to allow arbitrary number of windows.  Changed}
  38. {             version number to 1.0.}
  39. {  01/10/87    Ported to LightSpeed Pascal by Owen Hartnett                }
  40. {    Ωhm Software, 163 Richard Drive, Tiverton, RI 02878                }
  41. {  12/2/88    Made changes to add conditional compiling if you only need }
  42. {            one TransDisplay window.  Set the following cond variable        }
  43. {            singleDisplay to true if you want only one TransDisplay window }
  44. {            and want smaller code size.    Made adjustments for LSP 2.0    }
  45.  
  46. unit TransDisplay;
  47.  
  48. interface
  49.  
  50. {$SETC singleDisplay:=false }
  51.     uses
  52. {$IFC UNDEFINED THINK_PASCAL}
  53.         Memtypes, Quickdraw, OSIntf, ToolIntf, PackIntf, 
  54. {$ENDC}
  55.         TransSkel;
  56.  
  57.     procedure SetDWindow (theWind: WindowPtr);
  58.     procedure DisplayString (theStr: str255);
  59.     procedure DisplayHexLong (l: longint);
  60.     procedure DisplayHexInt (i: integer);
  61.     procedure DisplayHexChar (c: char);
  62.     procedure DisplayBoolean (b: Boolean);
  63.     procedure DisplayChar (c: char);
  64.     procedure DisplayInt (i: integer);
  65.     procedure DisplayLong (l: longint);
  66.     procedure DisplayLn;
  67.     procedure DisplayText (theText: Ptr; len: longint);
  68.     function GetNewDWindow (resourceNum: integer; behind: WindowPtr): WindowPtr;
  69.     function NewDWindow (bounds: Rect; title: Str255; visible: Boolean; behind: WindowPtr; goAway: Boolean; refcon: longint): WindowPTr;
  70.     procedure FlushDWindow (theWind: WindowPtr; byteCount: longint);
  71.     procedure GetDWindow (var theWind: WindowPtr);
  72.     procedure SetDWindowFlush (theWind: WindowPtr; maxText, flushAmt: longint);
  73.     procedure SetDWindowNotify (theWind: WindowPTr; p: ProcPtr);
  74.     procedure setDWindowPos (theWind: WindowPtr; lineNum: integer);
  75.     procedure SetDWindowStyle (theWind: WindowPtr; font, size, wrap, just: integer);
  76.     function GetDWindowTE (theWind: WindowPtr): TEHandle;
  77.     function IsDWindow (theWind: WindowPtr): Boolean;
  78.     procedure TransDisplayInit;
  79.  
  80. implementation
  81.  
  82. {    Display window types, constants, variables.}
  83.  
  84.     const
  85.         monaco = 4;
  86.  
  87. {$IFC not singleDisplay }
  88.     type
  89.         DIPtr = ^DisplayInfo;
  90.         DIHandle = ^DIPtr;
  91.         DisplayInfo = record
  92.                 dWind: WindowPtr;        { display window         }
  93.                 dTE: TEHandle;            { window text            }
  94.                 dScroll: ControlHandle;    { window scroll bar      }
  95.                 dActivate: ProcPtr;        { notification procedure }
  96.                 dMaxText: longint;        { max text length        }
  97.                 dFlushAmt: longint;        { amount to autoflush    }
  98.                 dNext: DIHandle;            { next window structure  }
  99.             end;
  100. {$ENDC}
  101.  
  102.     var
  103.  
  104. { Look at TransDisplayInit procedure for initial values of these variables    }
  105.  
  106.         d_font, d_size: integer;                    { default font              }
  107.                                                 { default pointsize         }
  108.         d_wrap, d_just: integer;                { default word wrap (on)    }
  109.                                                 { default justification     }
  110.         d_maxText, d_flushAmt: longint;        { default max text allowed  }
  111.                                                 { default autoflush amount  }
  112.         d_activate: ProcPtr;                    { default notification proc }
  113.  
  114. {    Lowest allowable values for autoflush characteristics}
  115.  
  116.  
  117.         d_loMaxText, d_loFlushAmt: longint;
  118.  
  119. {$IFC not singleDisplay }
  120.  
  121.         dwList: DIHandle;
  122.  
  123. {    Variables pertaining to the display window being operated on}
  124. {    (updated, resized, etc.).  This window is not necessarily the}
  125. {    same as curDispWind!  These variables are synced to the window}
  126. {    with SyncGlobals. }
  127.  
  128.         dispInfo: DIHandle;        { info structure         }
  129. {$ENDC}
  130.  
  131.         dispWind: WindowPtr;            { the window             }
  132.         dispTE: TEHandle;                { window text            }
  133.         dispScroll: ControlHandle;        { the scroll bar         }
  134.         dActivate: ProcPtr;                { notification procedure }
  135.         dMaxText, dFlushAmt: longint;        { max text allowed       }
  136.         { amount to flush        }
  137.  
  138. {    curDispWind is the current output window.}
  139. {    If curDispWind = nil, output is turned off.}
  140.  
  141.         curDispWind: WindowPtr;
  142.  
  143. { -------------------------------------------------------------------- }
  144. {                Miscellaneous Internal (private) Routines                }
  145. { -------------------------------------------------------------------- }
  146.  
  147.  
  148.  
  149. {    Draw grow box of dispWind in lower right hand corner}
  150.  
  151.     procedure DrawGrowBox;
  152.  
  153.         var
  154.             oldClip: RgnHandle;
  155.             r: Rect;
  156.  
  157.     begin
  158.         r := dispWind^.portRect;
  159.         r.left := r.right - 15;        { draw only in corner }
  160.         r.top := r.bottom - 15;
  161.         oldClip := NewRgn;
  162.         GetClip(oldClip);
  163.         ClipRect(r);
  164.         DrawGrowIcon(dispWind);
  165.         SetClip(oldClip);
  166.         DisposeRgn(oldClip);
  167.     end;
  168.  
  169.  
  170.  
  171.  
  172. { -------------------------------------------------------------------- }
  173. {            Lowest-level Internal (Private) Display Window Routines        }
  174. { -------------------------------------------------------------------- }
  175.  
  176. {$IFC not singleDisplay}
  177.  
  178. {    Get display window info associated with window.}
  179. {    Return nil if window isn't a known display window.}
  180.  
  181.     function GetDInfo (theWind: WindowPtr): DIHandle;
  182.         var
  183.             h: DIHandle;
  184.             foundit: Boolean;
  185.     begin
  186.         h := dwList;
  187.         foundit := false;
  188.         while (h <> nil) and not foundit do
  189.             begin
  190.                 if h^^.dWind = theWind then
  191.                     begin
  192.                         GetDInfo := h;
  193.                         h := nil;
  194.                         foundit := true;
  195.                     end
  196.                 else
  197.                     h := h^^.dNext;
  198.             end;
  199.         if not foundit then
  200.             GetDInfo := nil;                    {make it a nop    }
  201.     end;
  202. {$ENDC}
  203.  
  204. {$IFC singleDisplay}
  205.  
  206.     procedure SyncGlobals (theWind: WindowPtr);
  207.     begin
  208.     end;            { make it a nop }
  209.  
  210. {$ELSEC }
  211. {    Synchronize globals to a display window.  theWind must be a legal}
  212. {    display window, with one exception:  if theWind is nil, the}
  213. {    variables are synced to the current port.  That is safe (and}
  214. {    correct) because:}
  215. {    (i)     nil is only passed by display window handler procedures,}
  216. {         which are only called by TransSkel for display window}
  217. {         events.}
  218. {    (ii) TransSkel always sets the port to the window before}
  219. {         calling the handler proc.}
  220. {    Hence, use of the current port under these circumstances}
  221. {    always produces a legal display window.}
  222.  
  223. {    SyncGlobals is not used in single display mode, because the}
  224. {    globals are all set by SetupDWindow and do not change thereafter.}
  225.  
  226.     procedure SyncGlobals (theWind: WindowPtr);
  227.  
  228.         var
  229.             dp: DIPtr;
  230.     begin
  231.         if theWind = nil then                    { use current window }
  232.             GetPort(theWind);
  233.         dispWind := theWind;
  234.         dispInfo := GetDInfo(dispWind);
  235.         dp := dispInfo^;
  236.         dispScroll := dp^.dScroll;
  237.         dispTE := dp^.dTE;
  238.         dActivate := dp^.dActivate;
  239.         dMaxText := dp^.dMaxText;
  240.         dFlushAmt := dp^.dFlushAmt;
  241.     end;
  242. {$ENDC}
  243.  
  244. {    Calculate the dimensions of the editing rectangle for}
  245. {    dispWind (which must be set properly and is assumed to }
  246. {    the current port).  (The viewRect and destRect are the}
  247. {    same size .) Assumes the port , text font and text size are all}
  248. {    set properly.  The viewRect is sized so that an integral}
  249. {    number of lines can be displayed in it, i.e., so that a}
  250. {    partial line never shows at the bottom. }
  251.  
  252.     procedure CalcEditRect (var r: Rect);
  253.  
  254.         var
  255.             f: FontInfo;
  256.             lineHeight: integer;
  257.  
  258.     begin
  259.         GetFontInfo(f);
  260.         lineHeight := f.ascent + f.descent + f.leading;
  261.         r := dispWind^.portRect;
  262.         r.left := r.left + 4;
  263.         r.right := r.right - 17;            { leave room for scroll bar + 2 }
  264.         r.top := r.top + 2;
  265.         r.bottom := r.top + ((r.bottom - (r.top - 2)) div lineHeight) * lineHeight;
  266.     end;
  267.  
  268. {    Calculate the dimensions of the scroll bar rectangle for the}
  269. {    window.  Make sure that the edges overlap the window frame and}
  270. {    the grow box.}
  271.  
  272.     procedure CalcScrollRect (var r: Rect);
  273.  
  274.     begin
  275.         r := dispWind^.portRect;
  276.         r.right := r.right + 1;
  277.         r.left := r.right - 16;
  278.         r.top := r.top - 1;
  279.         r.bottom := r.bottom - 14;
  280.     end;
  281.  
  282. {    Calculate the number of lines currently scrolled off}
  283. {    the top.}
  284.  
  285.     function LinesOffTop: integer;
  286.  
  287.         var
  288.             ePtr: TEPtr;
  289.  
  290.     begin
  291.         ePtr := dispTE^;
  292.         LinesOffTop := (ePtr^.viewRect.top - ePtr^.destRect.top) div ePtr^.lineHeight;
  293.     end;
  294.  
  295. {    Highlight the scroll bar properly.  This means that it's not}
  296. {    made active if the window itself isn't active, even if}
  297. {    there's enough text to fill the window. }
  298.  
  299.     procedure HiliteScroll;
  300.         var
  301.             result: integer;
  302.     begin
  303.         if (GetCtlMax(dispScroll) > 0) and (dispWind = FrontWindow) then
  304.             result := 0
  305.         else
  306.             result := 255;
  307.         HiliteControl(dispScroll, result);
  308.     end;
  309.  
  310. {    Scroll to the correct position.  lDelta is the}
  311. {    amount to CHANGE the current scroll setting by.}
  312. {    Positive scrolls the text up, negative down.}
  313.  
  314.     procedure ScrollText (lDelta: integer);
  315.  
  316.         var
  317.             lHeight, newLine, topLine: integer;
  318.  
  319.     begin
  320.         lHeight := dispTE^^.lineHeight;
  321.         topLine := LinesOffTop;
  322.         newLine := topLine + lDelta;
  323.         if newLine < 0 then
  324.             newLine := 0;
  325.         if newLine > GetCtlmax(dispScroll) then
  326.             newLine := GetCtlMax(dispScroll);
  327.         SetCtlValue(dispScroll, newLine);
  328.         TEScroll(0, (topLine - newLine) * lHeight, dispTE);
  329.     end;
  330.  
  331.  
  332. {    Filter proc for tracking mousedown in scroll bar . The code}
  333. {    for the part originally hit is stored in the control 's reference}
  334. {    value by Mouse ( ) before calling this . }
  335.  
  336.  
  337. {    Scroll by one line if the mouse is in an arrow.  Scroll by a half}
  338. {    window's worth of lines if the mouse is in a page region. }
  339.  
  340.     procedure TrackScroll (theScroll: ControlHandle; partCode: integer);
  341.  
  342.         var
  343.             lDelta, halfPage: integer;
  344.  
  345.     begin
  346.         if partCode = GetCRefCon(theScroll) then        { still in same part? }
  347.             begin
  348.                 halfPage := ((dispTE^^.viewRect.bottom - dispTE^^.viewRect.top) div dispTE^^.lineHeight) div 2;
  349.                 if halfPage = 0 then
  350.                     halfPage := halfPage + 1;
  351.                 case partCode of
  352.                     inUpButton: 
  353.                         lDelta := -1;
  354.                     inDownButton: 
  355.                         lDelta := 1;
  356.                     inPageUp: 
  357.                         lDelta := -halfPage;
  358.                     inPageDown: 
  359.                         lDelta := halfPage;
  360.                     otherwise
  361.                 end;
  362.                 ScrollText(lDelta);
  363.             end;
  364.     end;
  365.  
  366. {    Adjust the text in the text record and the scroll bar.  This is}
  367. {    called for major catastrophes, such as resizing the window, or}
  368. {    changing the word wrap style.  It makes sure the view and}
  369. {    destination rectangles are sized properly, and that the bottom}
  370. {    line of text never scrolls up past the bottom line of the}
  371. {    window, if there's enough to fill the window, and that the}
  372. {    scroll bar max and current values are set properly.}
  373.  
  374. {    Resizing the dest rect just means resetting the right edge}
  375. {    (the top is NOT reset), since text might be scrolled off the}
  376. {    top (i.e., destRect.top != 0).}
  377.  
  378.     procedure OverhaulDisplay;
  379.  
  380.         var
  381.             r: Rect;
  382.             nLines, visLines, topLines, scrollLines, lHeight: integer;
  383.             { number of lines in TERec }
  384.         { number of lines displayable in window }
  385.         { number of lines currently scrolled off top }
  386.         { number of lines to scroll down }
  387.  
  388.     begin
  389.         CalcEditRect(r);
  390.         dispTE^^.destRect.right := r.right;
  391.         dispTE^^.viewRect := r;
  392.         TECalText(dispTE);        { recalc line starts }
  393.         lHeight := dispTE^^.lineHeight;
  394.         nLines := dispTE^^.nLines;
  395.         visLines := (r.bottom - r.top) div lheight;
  396.         topLines := LinesoffTop;
  397.  
  398. {    If the text doesn't fill the window (visLines > nLines - topLines),}
  399. {    pull the text down if possible (if topLines > 0).  Make sure}
  400. {    not to try to scroll down by more lines than are hidden off the top .}
  401.  
  402.         scrollLines := visLines - (nLines - topLines);
  403.         if (scrollLines > 0) and (topLines > 0) then
  404.             begin
  405.                 if scrollLines > topLines then
  406.                     scrollLines := topLines;
  407.                 TEScroll(0, scrollLInes * lHeight, dispTE);
  408.                 toplines := topLines - scrollLines;
  409.             end;
  410.         TEUpdate(r, dispTE);
  411.         if nLines - visLines < 0 then
  412.             SetCtlMax(dispScroll, 0)
  413.         else
  414.             SetCtlMax(dispScroll, nLines - VisLines);
  415.         SetCtlValue(dispScroll, topLines);
  416.         HiliteScroll;
  417.     end;
  418.  
  419.     procedure callpnoarg (myProc: ProcPtr);
  420.  
  421. { For all the Procedures that are called with no arguments                            }
  422.  
  423.     inline
  424.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  425.         $4e90;
  426.  
  427.     procedure callpBoolean (myBool: Boolean; myProc: ProcPtr);
  428.  
  429. { Two calls use Booleans as one parameter arguments.  This procedure handles    }
  430. { both of them.                                                                            }
  431.  
  432.     inline
  433.         $205f,     {movea.l  (a7)+,a0        ; (a0) is a ptr to string, 4(a0) is mode}
  434.         $4e90;
  435.  
  436. { ---------------------------------------------------------------- }
  437. {                        Window Handler Routines                        }
  438. { ---------------------------------------------------------------- }
  439.  
  440.  
  441.  
  442. {    When the window comes active, highlight the scroll bar appropriately.}
  443. {    When the window is deactivated, un-highlight the scroll bar.}
  444. {    Redraw the grow box.}
  445.  
  446. {    Notify the host as appropriate.}
  447.  
  448. {    Note that clicking close box hides the window, which generates a}
  449. {    deactivate event, so there is no need for a close notifier.}
  450.  
  451.  
  452.     procedure Activate (isActive: Boolean);
  453.  
  454.     begin
  455.         SyncGlobals(nil);                { sync to current port }
  456.         DrawGrowBox;
  457.         HiliteScroll;
  458.  
  459.         if dActivate <> nil then
  460.             callpBoolean(isActive, dActivate);
  461.     end;
  462.  
  463. {    Update window.  The update event might be in response to a}
  464. {    window resizing.  If so, move and resize the scroll bar,}
  465. {    and recalculate the text display.}
  466.  
  467. {    The ValidRect call is done because the HideControl adds the}
  468. {    control bounds box to the update region - which would generate}
  469. {    another update event!  Since everything is redrawn below anyway,}
  470. {    the ValidRect is used to cancel the update.}
  471.  
  472.     procedure Update (resized: Boolean);
  473.  
  474.         var
  475.             r: Rect;
  476.  
  477.     begin
  478.         SyncGlobals(nil);                    { sync to current port }
  479.         r := dispWind^.portRect;
  480.         EraseRect(r);
  481.         if resized then
  482.             begin
  483.                 HideControl(dispScroll);
  484.                 r := dispScroll^^.contrlRect;
  485.                 ValidRect(r);
  486.                 CalcScrollRect(r);
  487.                 SizeControl(dispScroll, 16, r.bottom - r.top);
  488.                 MoveControl(dispScroll, r.left, r.top);
  489.                 OverHaulDisplay;
  490.                 ShowControl(dispScroll);
  491.             end
  492.         else
  493.             begin
  494.                 r := dispTE^^.viewRect;
  495.                 TEUpdate(r, dispTE);
  496.             end;
  497.         DrawGrowBox;
  498.         DrawControls(dispWind);    { redraw scroll bar }
  499.     end;
  500.  
  501. {    Handle mouse clicks in window}
  502.  
  503.     procedure Mouse (thePt: Point; t: longint; mods: integer);
  504.  
  505.         var
  506.             thePart: integer;
  507.             oldCtlValue: integer;
  508.  
  509.     begin
  510.         SyncGlobals(nil);                    { Sync to current port    }
  511.         thePart := TestControl(dispScroll, thePt);
  512.         if thePart = inThumb then
  513.             begin
  514.                 OldCtlValue := GetCtlValue(dispScroll);
  515.                 if TrackControl(dispScroll, thePt, nil) = inThumb then
  516.                     ScrollText(GetCtlValue(dispScroll) - oldCtlValue);
  517.             end
  518.         else if thePart <> 0 then
  519.             begin
  520.                 SetCRefCon(dispScroll, longint(thePart));
  521.                 oldCtlValue := TrackControl(dispScroll, thePt, @TrackScroll);
  522.             end;
  523.     end;
  524.  
  525. {    Remove the display window from the list, and dispose of it.}
  526. {    Since the clobber procedure is never called except for real display}
  527. {    windows, and since the list must therefore be non-empty, it is}
  528. {    not necessary to check the legality of the window or that the}
  529. {    window's in the list.}
  530.  
  531. {    Must do SetDWindow (nil) to turn output off, if the window being}
  532. {    clobbered is the current output window.}
  533.  
  534.     procedure Clobber;
  535.  
  536.         var
  537. {$IFC not singleDisplay}
  538.             h, h2: DIHandle;
  539. {$ENDC}
  540.             keepgoing: Boolean;
  541.  
  542.     begin
  543.         SyncGlobals(nil);                    { sync to current port }
  544.         if dispWind = curDispWind then    { is it the first window in list? }
  545.             SetDWindow(nil);
  546. {$IFC not singleDisplay}
  547.         if dwList^^.dWind = dispWind then    { found it }
  548.             begin
  549.                 h2 := dwList;
  550.                 dwList := dwList^^.dNext;
  551.             end
  552.         else
  553.             begin
  554.                 h := dwList;
  555.                 keepgoing := true;
  556.                 while (h <> nil) and keepgoing do
  557.                     begin
  558.                         h2 := h^^.dNext;
  559.                         if h2^^.dWind = dispWind then
  560.                             begin
  561.                                 h^^.dNext := h2^^.dNext;
  562.                                 keepgoing := false;
  563.                             end;
  564.                         h := h2;
  565.                     end;
  566.             end;
  567.         DisposHandle(Handle(h2));        { get rid of information structure }
  568. {$ENDC}
  569.         TEDispose(dispTE);                { toss text record }
  570.         DisposeWindow(dispWind);        { toss window and scroll bar }
  571.         dispWind := nil;
  572.     end;
  573.  
  574. { ---------------------------------------------------------------- }
  575. {                            Control Routines                        }
  576. { ---------------------------------------------------------------- }
  577.  
  578.  
  579. {    Test whether a window is a legal display window or not }
  580.  
  581.     function IsDWindow;
  582.  
  583.     begin
  584. {$IFC singleDisplay}
  585.         IsDWindow := (theWind = dispWind) and (dispWind <> nil);
  586. {$ELSEC}
  587.         IsDWindow := GetDInfo(theWind) <> nil;
  588. {$ENDC}
  589.     end;
  590.  
  591. {    Return handle to display window's text record}
  592.  
  593.     function GetDWindowTE;
  594.  
  595. {$IFC not singleDisplay}
  596.  
  597.         var
  598.             dInfo: DIHandle;
  599. {$ENDC}
  600.  
  601.     begin
  602. {$IFC not singleDisplay}
  603.         if GetDInfo(theWind) = nil then
  604.             GetDWindowTE := nil
  605.         else
  606.             GetDWIndowTE := dInfo^^.dTE;
  607. {$ELSEC}
  608.         if ISDWindow(theWind) then
  609.             GetDWindowTE := dispTE
  610.         else
  611.             GetDWindowTE := nil;
  612. {$ENDC}
  613.     end;
  614.  
  615. {    Change the text display characteristics of a display window}
  616. {    and redisplay it.  As a side effect, this always scrolls to the}
  617. {    home position.}
  618.  
  619.     procedure SetDWindowStyle;
  620.  
  621.         var
  622.             savePort: GrafPtr;
  623.             f: FontInfo;
  624.             te: TEHandle;
  625.             r: Rect;
  626.  
  627.     begin
  628.         if theWind = nil then            { reset window creation defaults }
  629.             begin
  630.                 d_font := font;
  631.                 d_size := size;
  632.                 d_wrap := wrap;
  633.                 d_just := just;
  634.             end
  635.         else
  636.             begin
  637.                 if IsDWindow(theWind) then
  638.                     begin
  639.                         GetPort(savePort);
  640.                         SyncGlobals(theWind);
  641.                         SetPort(dispWind);
  642.                         te := dispTE;
  643.                         r := te^^.viewRect;
  644.                         EraseRect(r);
  645.                         r := te^^.destRect;    { scroll home without redrawing }
  646.  
  647.                         OffsetRect(r, 0, 2 - r.top);
  648.                         te^^.destRect := r;
  649.                         te^^.crOnly := wrap;    { set word wrap }
  650.                         TESetJust(just, te);    { set justification }
  651.                         TextFont(font);         { set the font and point size }
  652.                         TextSize(size);        { of text record (this is the }
  653.                         GetFontInfo(f);        { hard part) }
  654.                         te^^.lineHeight := f.ascent + f.descent + f.leading;
  655.                         te^^.fontAscent := f.ascent;
  656.                         te^^.txFont := font;
  657.                         te^^.txSize := size;
  658.  
  659.                         OverhaulDisplay;
  660.                         SetPort(savePort);
  661.                     end;
  662.             end;
  663.     end;
  664.  
  665. {    Scroll the text in the window so that line lineNum is at the top.}
  666. {    First line is line zero.}
  667.  
  668.     procedure setDWindowPos;
  669.  
  670.         var
  671.             savePort: GrafPtr;
  672.  
  673.     begin
  674.         if IsDWindow(theWind) then
  675.             begin
  676.                 GetPort(savePort);
  677.                 SyncGlobals(theWind);
  678.                 SetPort(dispWind);
  679.                 ScrollText(lineNum - GetCtlValue(dispScroll));
  680.                 SetPort(savePort);
  681.             end;
  682.     end;
  683.  
  684. {    Set display window activate notification procedure.}
  685. {    Pass nil to disable it.}
  686.  
  687.     procedure SetDWindowNotify;
  688. {$IFC not singleDisplay}
  689.         var
  690.             dInfo: DIHAndle;
  691. {$ENDC}
  692.  
  693.     begin
  694.         if theWind = nil then            { reset window creation default }
  695.             d_activate := p
  696.         else
  697.             begin
  698. {$IFC singleDisplay}
  699.                 if (ISDWindow(theWind)) then
  700.                     dActivate := p;
  701. {$ELSEC}
  702.                 dInfo := GetDInfo(theWind);
  703.                 if dInfo <> nil then
  704.                     dInfo^^.dActivate := p;
  705. {$ENDC}
  706.             end;
  707.     end;
  708.  
  709. {    Set display window autoflush characteristics}
  710.  
  711.     procedure SetDWindowFlush;
  712.  
  713. {$IFC not singleDisplay}
  714.         var
  715.             dInfo: DIHandle;
  716. {$ENDC}
  717.  
  718.     begin
  719.         if maxText > longint(32767) then
  720.             maxText := 32767;
  721.         if maxText < d_loMaxText then
  722.             maxText := d_loMaxText;
  723.         if flushAmt < d_loFlushAmt then
  724.             flushAmt := d_loFlushAmt;
  725.         if theWind = nil then
  726.             begin            { reset window creation defaults }
  727.                 d_maxText := maxText;
  728.                 d_flushAmt := flushAmt;
  729.             end
  730.         else
  731.             begin
  732. {$IFC singleDisplay}
  733.                 if (IsDWindow(theWind)) then
  734.                     begin
  735.                         dMaxText := maxText;
  736.                         dFlushAmt := flushAmt;
  737.                     end;
  738. {$ELSEC}
  739.                 dInfo := GetDInfo(theWind);
  740.                 if dInfo <> nil then
  741.                     begin
  742.                         dInfo^^.dMaxText := maxText;
  743.                         dInfo^^.dFlushAmt := flushAmt;
  744.                     end;
  745. {$ENDC}
  746.             end;
  747.     end;
  748.  
  749. {    Set which display window is to be used for output.  If theWind}
  750. {    is nil, output is turned off.  If theWind is not a legal display}
  751. {    window, nothing is done.}
  752.  
  753.     procedure SetDWindow;
  754.  
  755.     begin
  756.         if (theWind = nil) or IsDWindow(theWind) then
  757.             curDispWind := theWind;
  758.     end;
  759.  
  760. {    Get the WindowPtr of the current output display window.  If}
  761. {    output is turned off, this will be nil.}
  762.  
  763.     procedure GetDWindow;
  764.  
  765.     begin
  766.         theWind := curDispWind;
  767.     end;
  768.  
  769. {    Flush text from the window and readjust the display.}
  770.  
  771.     procedure FlushDWindow;
  772.  
  773.     begin
  774.         if IsDWindow(theWind) then
  775.             begin
  776.                 SyncGlobals(theWind);
  777.                 TESetSelect(longint(0), byteCount, dispTE);    { select text }
  778.                 TEDelete(dispTE);                                { clobber it }
  779.                 OverhaulDisplay;
  780.             end;
  781.     end;
  782.  
  783. {    Create and initialize a display window and the associated data}
  784. {    structures, and return the window pointer.  Install window in}
  785. {    list of display windows.}
  786.  
  787.     procedure SetupDWindow;
  788.  
  789.         var
  790.             r: Rect;
  791.             savePort: GrafPtr;
  792. {$IFC not singleDisplay}
  793.             dInfo: DIHandle;
  794. {$ENDC}
  795.             dummy: Boolean;
  796.  
  797.     begin
  798.         dummy := SkelWindow(dispWind, @Mouse, nil, @Update, @Activate, nil, @Clobber, nil, false);
  799.     { the window }
  800.         { mouse click handler }
  801.         { key clicks are ignored }
  802.         { window updating procedure }
  803.         { window activate/deactivate procedure }
  804.         { TransSkel hides window if no close proc }
  805.         { (generates deactivate event) }
  806.         { window disposal procedure }
  807.         { no idle proc }
  808.         { irrelevant since no idle proc }
  809.  
  810. {    Build the scroll bar.  Make sure the borders overlap the}
  811. {    window frame and the frame of the grow box.}
  812.  
  813.         CalcScrollRect(r);
  814.         dispScroll := NewControl(dispWind, r, '', true, 0, 0, 0, scrollBarProc, longint(0));
  815.  
  816. {    Create the TE record used for text display.  Use defaults for}
  817. {    display characteristics.  Setting window style overhauls}
  818. {    display, so can cancel and update event pending for the window.}
  819.  
  820.         CalcEditRect(r);
  821.         dispTE := TENew(r, r);
  822.  
  823. {$IFC not singleDisplay}
  824. {    Get new information structure, attach to list of known display}
  825. {    windows.}
  826.  
  827.         dInfo := DIHandle(NewHandle(sizeof(DisplayInfo)));
  828.  
  829.         dInfo^^.dNext := dwList;
  830.         dwList := dInfo;
  831.         dInfo^^.dWind := dispWind;
  832.         dInfo^^.dScroll := dispScroll;
  833.         dInfo^^.dTE := dispTE;
  834. {$ENDC}
  835.  
  836.         SetDWindowNotify(dispWind, d_activate);
  837.         SetDWindowFlush(dispWind, d_maxtext, d_flushAmt);
  838.         SetDWindowStyle(dispWind, d_font, d_size, d_wrap, d_just);
  839.  
  840. {    Make window current display output window}
  841.  
  842.         SetDWindow(dispWind);
  843.     end;
  844.  
  845. {    Create and initialize a display window and the associated data}
  846. {    structures, and return the window pointer.  Install window in}
  847. {    list of display windows.  In single-window mode, disallow}
  848. {    creation of a new window if one already exists.}
  849.  
  850. {    The parameters are similar to those for NewWindow.  See Inside}
  851. {    Macintosh.}
  852.  
  853.     function NewDWindow;
  854.  
  855.     begin
  856. {$IFC singleDisplay}
  857.         if dispWind <> nil then
  858.             NewDWindow := nil
  859.         else
  860. {$ENDC}
  861.             begin
  862.                 dispWind := NewWindow(nil, bounds, title, visible, documentProc, behind, goAway, refCon);
  863.                 SetUpDWindow;
  864.                 NewDWindow := dispWind;
  865.             end;
  866.     end;
  867.  
  868. {    Create and initialize a display window (using a resource) and}
  869. {    the associated data structures, and return the window pointer.}
  870. {    Install window in list of display windows.  In single-window}
  871. {    mode, disallow creation of a new window if one already exists.}
  872.  
  873. {    The parameters are similar to those for GetNewWindow.  See Inside}
  874. {    Macintosh.}
  875.  
  876.     function GetNewDWindow;
  877.  
  878.     begin
  879. {$IFC singleDisplay}
  880.         if dispWind <> nil then
  881.             GetNewDWindow := nil
  882.         else
  883. {$ENDC}
  884.             begin
  885.                 dispWind := GetNewWindow(resourceNum, nil, behind);
  886.                 SetUPDWindow;
  887.                 GetNewDWindow := dispWind;
  888.             end;
  889.     end;
  890.  
  891. { ------------------------------------------------------------ }
  892. {                        Output Routines                            }
  893. { ------------------------------------------------------------ }
  894.  
  895.  
  896. {}
  897. {    Write text to display area if output is on (curDispWind != nil).}
  898. {    DisplayText is the fundamental output routine.  All other}
  899. {    output calls map (eventually) to it.}
  900.  
  901. {    First check whether the insertion will cause overflow and flush}
  902. {    out some stuff if so.  Insert new text at the end, then test}
  903. {    whether lines must be scrolled to get the new stuff to show up.}
  904. {    If yes, then do the scroll.  Set values of scroll bar properly}
  905. {    and highlight as appropriate.}
  906.  
  907. {    The current port is preserved.  Since all output calls end up}
  908. {    here, it's the only output routine that has to save the port}
  909. {    and check whether output is on.}
  910.  
  911.     procedure DisplayText;
  912.  
  913.         var
  914.             nLines, dispLines, topLines, scrollLines, lHeight: integer;
  915.         { number of lines in TERec }
  916.         { number of lines displayable in window }
  917.         { number of lines currently scrolled off top }
  918.         { number of lines to scroll up }
  919.             r: Rect;
  920.             savePort: GrafPtr;
  921.             dTE: TEHandle;
  922.  
  923.     begin
  924.         if curDispWind <> nil then
  925.             begin
  926.                 GetPort(savePort);
  927.                 SetPort(curDispWind);
  928.                 SyncGlobals(curDispWind);
  929.                 dTE := dispTE;
  930.  
  931.                 if dTE^^.teLength + len > dMaxText then    { check overflow }
  932.                     begin
  933.                         FlushDWindow(dispWind, dFlushAmt);
  934.                         DisplayString('(autoflush occurred)');
  935.                     end;
  936.                 lHeight := dTE^^.lineHeight;
  937.                 TESetSelect(longint(32767), longint(32767), dTE);
  938.                 TEInsert(theText, len, dTE);
  939.                 r := dTE^^.viewRect;
  940.                 nLines := dTE^^.nLines;
  941.                 dispLines := (r.bottom - r.top) div lHeight;
  942.                 topLines := LinesOffTop;
  943.                 scrollLines := nLines - (topLines + dispLines);
  944.                 if scrollLines > 0 then                                 { must scroll up }
  945.                     TEScroll(0, -lHeight * scrollLines, dTE);            { scroll up }
  946.                 topLines := nLines - dispLines;
  947.                 if (topLines >= 0) and (GetCtlMax(dispScroll) <> topLines) then
  948.                     begin
  949.                         SetCtlMax(dispScroll, topLines);
  950.                         SetCtlValue(dispScroll, topLines);
  951.                     end;
  952.                 HiliteScroll;
  953.                 SetPort(savePort);
  954.             end;
  955.     end;
  956.  
  957. {    Derived output routines:}
  958.  
  959. {    DisplayString    Write (Pascal) string}
  960.  
  961. {    DisplayLong        Write value of long integer}
  962. {    DisplayInt        Write value of integer}
  963. {    DisplayChar        Write character}
  964.  
  965. {    DisplayHexLong    Write value of long integer in hex (8 digits)}
  966. {    DisplayHexInt    Write value of integer in hex (4 digits)}
  967. {    DisplayHexChar    Write value of character in hex (2 digit)}
  968.  
  969. {    DisplayBoolean    Write boolean value}
  970. {    DisplayLn        Write carriage return}
  971.  
  972.     procedure DisplayString;
  973.  
  974.         var
  975.             myPtr: Ptr;
  976.  
  977.     begin
  978.         myPtr := Ptr(longint(@theStr) + 1);
  979.         DisplayText(myPtr, longint(length(theSTr)));
  980.     end;
  981.  
  982.     procedure DisplayLong;
  983.  
  984.         var
  985.             s: Str255;
  986.  
  987.     begin
  988.         NumToString(l, s);
  989.         DisplayString(s);
  990.     end;
  991.  
  992.     procedure DisplayInt;
  993.  
  994.     begin
  995.         DisplayLong(longint(i));
  996.     end;
  997.  
  998.     procedure DisplayChar;
  999.  
  1000.         var
  1001.             myPtr: Ptr;
  1002.  
  1003.     begin
  1004.         myPtr := @c;
  1005.         myPtr := Ptr(longint(myPtr) + 1);
  1006.         DisplayText(myPtr, longint(1));
  1007.     end;
  1008.  
  1009.     procedure DisplayLn;
  1010.  
  1011.     begin
  1012.         DisplayChar(char(13));
  1013.     end;
  1014.  
  1015.     procedure DisplayBoolean;
  1016.  
  1017.     begin
  1018.         if b then
  1019.             DisplayString('True')
  1020.         else
  1021.             DisplayString('False');
  1022.     end;
  1023.  
  1024.     procedure HexByte (value: integer);    {value should be 0..15}
  1025.     begin
  1026.         if value < 10 then
  1027.             DisplayChar(char(value + integer('0')))
  1028.         else
  1029.             DisplayChar(char(value + (integer('a') - 10)));
  1030.     end;
  1031.  
  1032.     procedure DisplayHexChar;
  1033.  
  1034.     begin
  1035.         HexByte(integer(BitAnd(BitShift(longint(c), -4), $0000000f)));
  1036.         HexByte(integer(BitAnd(longint(c), $0000000f)));
  1037.     end;
  1038.  
  1039.     procedure DisplayHexInt;
  1040.  
  1041.     begin
  1042.         DisplayHexChar(char(BitAnd(BitShift(longint(i), -8), $000000ff)));
  1043.         DisplayHexChar(char(BitAnd(longint(i), $000000ff)));
  1044.     end;
  1045.  
  1046.     procedure DisplayHexLong;
  1047.  
  1048.     begin
  1049.         DisplayHexInt(Integer(BitAnd(BitShift(l, -16), $0000ffff)));
  1050.         DisplayHexInt(integer(LoWord(l)));
  1051.     end;
  1052.  
  1053.     procedure TransDisplayInit;
  1054.  
  1055.     begin
  1056.  
  1057. {    Default values for display window characteristics}
  1058.  
  1059.         d_font := monaco;        { default font              }
  1060.         d_size := 9;                { default pointsize         }
  1061.         d_wrap := 0;                { default word wrap (on)    }
  1062.         d_just := teJustLeft;    { default justification     }
  1063.         d_maxText := 30000;    { default max text allowed  }
  1064.         d_flushAmt := 25000;    { default autoflush amount  }
  1065.         d_activate := nil;        { default notification proc }
  1066.  
  1067. {    Lowest allowable values for autoflush characteristics}
  1068.  
  1069.         d_loMaxText := 100;
  1070.         d_loFlushAmt := 100;
  1071.  
  1072. {    dwList points to a list of structures describing the known display}
  1073. {    windows.}
  1074.  
  1075. {    curDispWind is the current output window.}
  1076. {    If curDispWind = nil, output is currently turned off.}
  1077.  
  1078. {$IFC not singleDisplay}
  1079.         dwList := nil;
  1080. {$ENDC}
  1081.         dispWind := nil;
  1082.         curDispWind := nil;
  1083.     end;
  1084. end.